#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "Calculate.hpp"

using namespace protocol_ns;
using call_back_t = std::function<Response(const Request &)>;

class Service
{
public:
    Service(call_back_t cb) : _cb(cb) {}

    void ServiceHelper(socket_sprt sockptr, InetAddr client) // 通过fd与client进行通信
    {
        int fd = sockptr->SockFd();
        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]";
        LOG(DEBUG, "get a new link, info: fd is %d, %s", fd, clientaddr.c_str());

        std::string inbuffer;
        while (true)
        {
            sleep(5); // 故意延迟5s读取，保证一次能读取多条报文
            // 1.读取数据
            Request req;
            int n = sockptr->Recv(&inbuffer);
            // 客户端退出||出错
            if (n <= 0)
            {
                LOG(DEBUG, "client %s quit", clientaddr.c_str());
                break;
            }
            // inbuffer中存放多个报文
            while (true)
            {
                std::cout << "----begin----\n";
                std::cout << "inbuffer:" << inbuffer << std::endl;
                // 2.分析数据，得到完整的报文
                std::string str = Decode(inbuffer);
                // 没有读到完整的请求，继续往后读
                if (str.empty())
                    break;
                std::cout << "request:\n"
                          << str << std::endl;

                // 3.str一定是一个json串，对其进行反序列化
                req.Deserialize(str);

                // 4.业务处理
                Response rep = _cb(req);

                // 5.对rep进行序列化
                std::string send_str;
                rep.Serialize(&send_str);
                std::cout << "response Serialize:\n"
                          << send_str << std::endl;
                // 6.对序列化后的响应添加报头，变成一个完整的报文
                send_str = Encode(send_str);
                std::cout << "response Encode:\n"
                          << send_str << std::endl;

                // 7. 发送响应
                sockptr->Send(send_str); // 暂时不对发送做处理
            }
        }
    }

private:
    call_back_t _cb;
};

void Usage(std::string pro)
{
    std::cout << "Usage:\n\t" << pro << "local_port\n";
}

int main(int argn, char *argv[])
{
    if (argn < 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERROR);
    }
    uint16_t port = std::stoi(argv[1]);
    // 业务模块
    Calculate calculate;
    Service service(std::bind(&Calculate::Excute, &calculate, std::placeholders::_1));

    // 网络模块
    io_service_t service_helper = std::bind(&Service::ServiceHelper, &service, std::placeholders::_1, std::placeholders::_2);
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service_helper);
    tsvr->Loop();
    return 0;
}